library(tidyverse)
Lecture
f <- read.csv2("../data/obs_artif_conso_com_2009_2020_V2.csv", sep=",", encoding = "UTF-8")
Colonnes utiles
Stats départementales
statDep <- f %>%
group_by(iddep, iddeptxt) %>%
summarize(artact0920 = sum(artact0920),
arthab0920 = sum(arthab0920),
artmix0920 = sum(arthab0920),
artinc0920 = sum(arthab0920)) %>%
ungroup() %>%
data.frame()
`summarise()` has grouped output by 'iddep'. You can override using the `.groups` argument.
Stats régionales
statReg <- f %>%
group_by(idreg, idregtxt) %>%
summarize(artact0920 = sum(artact0920),
arthab0920 = sum(arthab0920),
artmix0920 = sum(artmix0920),
artinc0920 = sum(artinc0920)) %>%
ungroup() %>%
data.frame()
`summarise()` has grouped output by 'idreg'. You can override using the `.groups` argument.
!! Préparation des données Préparation des données
statReg2 <- gather(statReg,
"variable",
"flux",
c("artact0920", "arthab0920", "artmix0920", "artinc0920"))
Représentation en barres
library(ggplot2)
ggplot(data = statReg2, aes(x = idregtxt, y = flux, fill = variable)) +
geom_bar(stat = "identity", position = "stack") # on change le type ici

On crée le plot mais en horizontal :
library(ggplot2)
ggplot(data = statReg2,
aes(x = idregtxt,
y = flux,
fill = variable)) +
geom_bar(stat = "identity", position = "stack") +
coord_flip()

On effectue encore quelques modifications :
library(ggplot2)
statReg2$idregtxt <- factor(statReg2$idregtxt, levels = sort(unique(statReg2$idregtxt), decreasing = TRUE))
statReg2$variable <- factor(statReg2$variable, levels = c("arthab0920","artact0920", "artmix0920", "artinc0920"))
ggplot(data = statReg2,
aes(x = idregtxt,
y = flux,
fill = variable)) +
geom_bar(stat = "identity", position = "stack") +
coord_flip() +
theme(
# axis.text.x=element_blank(),
# axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
panel.background=element_blank(),
panel.border=element_blank(),
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
legend.title=element_text(size = 8),
legend.text=element_text(size = 8)) +
scale_fill_discrete( # !! scale_fill
name = "Flux\nd'artificialisation\n2009-2020",
labels = c("Habitat", "Activité", "Mixte", "Inconnu")
)

Couleurs Sélectionnons d’autres couleurs, plus neutres. Pour cela, utilisons la modélisation des couleurs Hue Chroma Luminance
http://hclwizard.org:3000/hclcolorpicker/
Le type de couleur est défini par hue, ou la teinte.
- Pour le type activité, nous choisirons la couleur rouge (hue de 5)
- Pour le type habitat, la couleur rouge (hue de 220)
- pour le type mixte, la couleur magenta (en quelque sorte un mélange du rouge et du bleu) (hue de 270)
- Nous représenterons le type inconnu par du gris
Nous choisissons un chroma de 30 (chroma va de 0 à 360 pour les couleurs les plus vives). Gris a un chroma de 0.
Nous choisissons une luminance de 80 (la luminosité va de 0 à 100 pour les couleurs les plus lumineuses).
En affectant les mêmes niveaux de chroma et de luminance, nous obteons une palette homogène.
getColorForHue <- function(h, c = 50, l = 80) {
hcl(h = h, c = c, l = l, fixup = TRUE)
}
colorRed <- getColorForHue(4)
colorBlue <- getColorForHue(220)
colorMagenta <- getColorForHue(300)
colorGrey <- hcl(h = 0, c = 0, l = 80, fixup = TRUE)
palette <- c(colorBlue, colorRed, colorMagenta, colorGrey)
names(palette) <- c("blue", "red", "magenta", "grey")
demoplot(palette, "bar")

Voici une représentation des couleurs :
hclplot(palette)
Refaisons le plot, mais avec ces nouvelles couleurs :
library(ggplot2)
ggplot(data = statReg2,
aes(x = idregtxt,
y = flux,
fill = variable)) +
geom_bar(stat = "identity", position = "stack") +
coord_flip() +
theme(
axis.ticks.y=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
panel.background=element_blank(),
panel.border=element_blank(),
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
legend.title=element_text(size = 8),
legend.text=element_text(size = 8)) +
scale_fill_manual(
name = "Flux\nd'artificialisation\n2009-2020",
labels = c("Habitat", "Activité", "Mixte", "Inconnu"),
values = c(colorBlue, colorRed, colorMagenta, colorGrey)
)

Les zones mixtes sont peu lisibles. Utilisons un chroma plus conséquent pour cette couleur :
library(ggplot2)
ggplot(data = statReg2,
aes(x = idregtxt,
y = flux,
fill = variable)) +
geom_bar(stat = "identity", position = "stack") +
coord_flip() +
theme(
axis.ticks.y=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
panel.background=element_blank(),
panel.border=element_blank(),
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
legend.title=element_text(size = 8),
legend.text=element_text(size = 8)) +
scale_fill_manual(
name = "Flux\nd'artificialisation\n2009-2020",
labels = c("Habitat", "Activité", "Mixte", "Inconnu"),
values = c(colorBlue, colorRed, getColorForHue(h = 300, c = 100), colorGrey)
)

Représentation en barres par département pour une région
Faisons le même graphique, mais pour tous les départements de Provence.
Transformons nos stats départementales.
Nous allons en profiter pour rendre les choses un peu plus génériques.
Tout d’abord, les deux premières colonnes correspondent aux code et libellés. Les autres colonnes concernent les flux.
statDep2 <- gather(statDep,
"variable",
"flux",
c("artact0920", "arthab0920", "artmix0920", "artinc0920"))
statDep3 <- statDep2 %>% rename(code = 1, libelle = 2)
Nous trions les niveaux de facteurs car ceux-ci déterminent l’ordre dans lequel les éléments sont affichés dans le graphique.
Nous souhaitons régler l’affichage des entités selon leur nom (départements ou régions), ainsi que celui des variables (flux d’habitat, activité, …)
!!!
Créons une fonction qui produit le graphique sur la base de ce data frame générique. On reprend le code précédent :
makePlot <- function(df) {
# Relevel
df$libelle <- as.character(df$libelle)
df$libelle <- factor(df$libelle, levels = sort(unique(df$libelle), decreasing = TRUE))
df$variable <- as.character(df$variable)
df$variable <- factor(df$variable, levels = c("arthab0920","artact0920", "artmix0920", "artinc0920"))
# Colors
colorBlue <- getColorForHue(220)
colorRed <- getColorForHue(4)
colorMagenta <- getColorForHue(h = 300, c = 100)
colorGrey <- hcl(h = 0, c = 0, l = 80, fixup = TRUE)
palette <- c(colorBlue, colorRed, colorMagenta, colorGrey)
# Plot
ggplot(data = df,
aes(x = libelle,
y = flux,
fill = variable)) +
geom_bar(stat = "identity", position = "stack") +
coord_flip() +
theme(
axis.ticks.y = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.background = element_blank(),
panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.title = element_text(size = 8),
legend.text = element_text(size = 8)) +
scale_fill_manual(
name = "Flux\nd'artificialisation\n2009-2020",
labels = c("Habitat", "Activité", "Mixte", "Inconnu"),
values = palette
)
}
makePlot(statDep3 %>% filter(code %in% c("04", "05", "06", "13", "83", "84")))
Nous pouvons utiliser cette fonction sur les stats régionales :
statReg2 %>% rename(code = 1, libelle = 2) %>% makePlot()

On peut donc utiliser la même fonction sur n’importe quel fichier statistiques de flux. Nous pourrions aussi l’utiliser sur des communes :
!!! !! data2viz !! styles ## Représentation en treemap La représentation en treemap est pas mal pour présenter les flux d’artificialisation sur une commune.
Prenons par exemple la commune d’Aix en Provence :
fAix <- f %>% filter(idcom == "13001") %>% select("arthab0920", "artact0920", "artmix0920", "artinc0920")
Le package plotly permet de créer ce style de représentation
treemap attend … !!!
library(plotly)
labels = c("Habitat", "Activité", "Mixte", "NC")
parents = c("", "", "", "")
values = as.numeric(fAix)
fig <- plot_ly(
type="treemap",
labels=labels,
parents=parents,
values=values,
marker=list(colorscale='Reds'))
fig
!!! pour plusieurs communes
Représentation en streamgraph
Voyons l’évolution au cours du temps des flux
LS0tDQp0aXRsZTogIkRhdGF2aXogTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQoNCkxlY3R1cmUNCmBgYHtyfQ0KZiA8LSByZWFkLmNzdjIoIi4uL2RhdGEvb2JzX2FydGlmX2NvbnNvX2NvbV8yMDA5XzIwMjBfVjIuY3N2Iiwgc2VwPSIsIiwgZW5jb2RpbmcgPSAiVVRGLTgiKQ0KDQpgYGANCg0KQ29sb25uZXMgdXRpbGVzDQoNClN0YXRzIGTDqXBhcnRlbWVudGFsZXMNCmBgYHtyfQ0Kc3RhdERlcCA8LSBmICU+JSANCiAgZ3JvdXBfYnkoaWRkZXAsIGlkZGVwdHh0KSAlPiUgDQogIHN1bW1hcml6ZShhcnRhY3QwOTIwID0gc3VtKGFydGFjdDA5MjApLA0KICAgICAgICAgICAgYXJ0aGFiMDkyMCA9IHN1bShhcnRoYWIwOTIwKSwNCiAgICAgICAgICAgIGFydG1peDA5MjAgPSBzdW0oYXJ0aGFiMDkyMCksDQogICAgICAgICAgICBhcnRpbmMwOTIwID0gc3VtKGFydGhhYjA5MjApKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUNCiAgZGF0YS5mcmFtZSgpDQoNCmBgYA0KDQpTdGF0cyByw6lnaW9uYWxlcw0KYGBge3J9DQpzdGF0UmVnIDwtIGYgJT4lIA0KICBncm91cF9ieShpZHJlZywgaWRyZWd0eHQpICU+JSANCiAgc3VtbWFyaXplKGFydGFjdDA5MjAgPSBzdW0oYXJ0YWN0MDkyMCksDQogICAgICAgICAgICBhcnRoYWIwOTIwID0gc3VtKGFydGhhYjA5MjApLA0KICAgICAgICAgICAgYXJ0bWl4MDkyMCA9IHN1bShhcnRtaXgwOTIwKSwNCiAgICAgICAgICAgIGFydGluYzA5MjAgPSBzdW0oYXJ0aW5jMDkyMCkpICU+JSANCiAgdW5ncm91cCgpICU+JQ0KICBkYXRhLmZyYW1lKCkNCg0KYGBgDQoNCiEhIFByw6lwYXJhdGlvbiBkZXMgZG9ubsOpZXMNClByw6lwYXJhdGlvbiBkZXMgZG9ubsOpZXMNCmBgYHtyfQ0Kc3RhdFJlZzIgPC0gZ2F0aGVyKHN0YXRSZWcsIA0KICAgICAgICJ2YXJpYWJsZSIsIA0KICAgICAgICJmbHV4IiwgDQogICAgICAgYygiYXJ0YWN0MDkyMCIsICJhcnRoYWIwOTIwIiwgImFydG1peDA5MjAiLCAiYXJ0aW5jMDkyMCIpKQ0KYGBgDQoNClJlcHLDqXNlbnRhdGlvbiBlbiBiYXJyZXMNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCmdncGxvdChkYXRhID0gc3RhdFJlZzIsIGFlcyh4ID0gaWRyZWd0eHQsIHkgPSBmbHV4LCBmaWxsID0gdmFyaWFibGUpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICMgb24gY2hhbmdlIGxlIHR5cGUgaWNpDQpgYGANCg0KT24gY3LDqWUgbGUgcGxvdCBtYWlzIGVuIGhvcml6b250YWwgOg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCmdncGxvdChkYXRhID0gc3RhdFJlZzIsIA0KICAgICAgIGFlcyh4ID0gaWRyZWd0eHQsIA0KICAgICAgICAgICB5ID0gZmx1eCwgDQogICAgICAgICAgIGZpbGwgPSB2YXJpYWJsZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIikgKw0KICBjb29yZF9mbGlwKCkNCmBgYA0KT24gZWZmZWN0dWUgZW5jb3JlIHF1ZWxxdWVzIG1vZGlmaWNhdGlvbnMgOg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCnN0YXRSZWcyJGlkcmVndHh0IDwtIGZhY3RvcihzdGF0UmVnMiRpZHJlZ3R4dCwgbGV2ZWxzID0gc29ydCh1bmlxdWUoc3RhdFJlZzIkaWRyZWd0eHQpLCBkZWNyZWFzaW5nID0gVFJVRSkpDQoNCnN0YXRSZWcyJHZhcmlhYmxlIDwtIGZhY3RvcihzdGF0UmVnMiR2YXJpYWJsZSwgbGV2ZWxzID0gYygiYXJ0aGFiMDkyMCIsImFydGFjdDA5MjAiLCAiYXJ0bWl4MDkyMCIsICJhcnRpbmMwOTIwIikpDQoNCmdncGxvdChkYXRhICA9IHN0YXRSZWcyLCANCiAgICAgICBhZXMoeCA9IGlkcmVndHh0LCANCiAgICAgICAgICAgeSA9IGZsdXgsIA0KICAgICAgICAgICBmaWxsID0gdmFyaWFibGUpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGhlbWUoDQogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ib3JkZXI9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCkpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSggIyAhISBzY2FsZV9maWxsDQogIG5hbWUgPSAiRmx1eFxuZCdhcnRpZmljaWFsaXNhdGlvblxuMjAwOS0yMDIwIiwNCiAgbGFiZWxzID0gYygiSGFiaXRhdCIsICJBY3Rpdml0w6kiLCAiTWl4dGUiLCAiSW5jb25udSIpDQogICkNCmBgYA0KDQoNCkNvdWxldXJzDQpTw6lsZWN0aW9ubm9ucyBkJ2F1dHJlcyBjb3VsZXVycywgcGx1cyBuZXV0cmVzLiBQb3VyIGNlbGEsIHV0aWxpc29ucyBsYSBtb2TDqWxpc2F0aW9uIGRlcyBjb3VsZXVycyBIdWUgQ2hyb21hIEx1bWluYW5jZQ0KDQpodHRwOi8vaGNsd2l6YXJkLm9yZzozMDAwL2hjbGNvbG9ycGlja2VyLw0KDQpMZSB0eXBlIGRlIGNvdWxldXIgZXN0IGTDqWZpbmkgcGFyIGh1ZSwgb3UgbGEgdGVpbnRlLiAgDQoNCi0gUG91ciBsZSB0eXBlIGFjdGl2aXTDqSwgbm91cyBjaG9pc2lyb25zIGxhIGNvdWxldXIgPHNwYW4gc3R5bGU9J2NvbG9yOnJlZCc+cm91Z2U8L3NwYW4+IChodWUgZGUgNSkNCi0gUG91ciBsZSB0eXBlIGhhYml0YXQsIGxhIGNvdWxldXIgPHNwYW4gc3R5bGU9J2NvbG9yOnJlZCc+cm91Z2U8L3NwYW4+IChodWUgZGUgMjIwKQ0KLSBwb3VyIGxlIHR5cGUgbWl4dGUsIGxhIGNvdWxldXIgbWFnZW50YSAoZW4gcXVlbHF1ZSBzb3J0ZSB1biBtw6lsYW5nZSBkdSByb3VnZSBldCBkdSBibGV1KSAoaHVlIGRlIDI3MCkNCi0gTm91cyByZXByw6lzZW50ZXJvbnMgbGUgdHlwZSBpbmNvbm51IHBhciBkdSBncmlzDQoNCk5vdXMgY2hvaXNpc3NvbnMgdW4gY2hyb21hIGRlIDMwIChjaHJvbWEgdmEgZGUgMCDDoCAzNjAgcG91ciBsZXMgY291bGV1cnMgbGVzIHBsdXMgdml2ZXMpLiBHcmlzIGEgdW4gY2hyb21hIGRlIDAuICAgDQpOb3VzIGNob2lzaXNzb25zIHVuZSBsdW1pbmFuY2UgZGUgODAgKGxhIGx1bWlub3NpdMOpIHZhIGRlIDAgw6AgMTAwIHBvdXIgbGVzIGNvdWxldXJzIGxlcyBwbHVzIGx1bWluZXVzZXMpLg0KDQpFbiBhZmZlY3RhbnQgbGVzIG3Dqm1lcyBuaXZlYXV4IGRlIGNocm9tYSBldCBkZSBsdW1pbmFuY2UsIG5vdXMgb2J0ZW9ucyB1bmUgcGFsZXR0ZSBob21vZ8OobmUuDQoNCmBgYHtyfQ0KZ2V0Q29sb3JGb3JIdWUgPC0gZnVuY3Rpb24oaCwgYyA9IDUwLCBsID0gODApIHsNCiAgaGNsKGggPSBoLCBjID0gYywgbCA9IGwsIGZpeHVwID0gVFJVRSkNCn0NCg0KY29sb3JCbHVlIDwtIGdldENvbG9yRm9ySHVlKDIyMCkNCmNvbG9yUmVkIDwtIGdldENvbG9yRm9ySHVlKDQpDQpjb2xvck1hZ2VudGEgPC0gZ2V0Q29sb3JGb3JIdWUoMzAwKQ0KY29sb3JHcmV5IDwtIGhjbChoID0gMCwgYyA9IDAsIGwgPSA4MCwgZml4dXAgPSBUUlVFKQ0KDQpwYWxldHRlIDwtIGMoY29sb3JCbHVlLCBjb2xvclJlZCwgY29sb3JNYWdlbnRhLCBjb2xvckdyZXkpDQpuYW1lcyhwYWxldHRlKSA8LSBjKCJibHVlIiwgInJlZCIsICJtYWdlbnRhIiwgImdyZXkiKQ0KDQpkZW1vcGxvdChwYWxldHRlLCAiYmFyIikNCmBgYA0KVm9pY2kgdW5lIHJlcHLDqXNlbnRhdGlvbiBkZXMgY291bGV1cnMgOg0KDQpgYGB7cn0NCmhjbHBsb3QocGFsZXR0ZSkNCmBgYA0KDQpSZWZhaXNvbnMgbGUgcGxvdCwgbWFpcyBhdmVjIGNlcyBub3V2ZWxsZXMgY291bGV1cnMgOg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCmdncGxvdChkYXRhICA9IHN0YXRSZWcyLCANCiAgICAgICBhZXMoeCA9IGlkcmVndHh0LCANCiAgICAgICAgICAgeSA9IGZsdXgsIA0KICAgICAgICAgICBmaWxsID0gdmFyaWFibGUpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGhlbWUoDQogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ib3JkZXI9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZSA9IDgpLA0KICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZSA9IDgpKSArDQpzY2FsZV9maWxsX21hbnVhbCgNCiAgbmFtZSA9ICJGbHV4XG5kJ2FydGlmaWNpYWxpc2F0aW9uXG4yMDA5LTIwMjAiLA0KICBsYWJlbHMgPSBjKCJIYWJpdGF0IiwgIkFjdGl2aXTDqSIsICJNaXh0ZSIsICJJbmNvbm51IiksDQogIHZhbHVlcyA9IGMoY29sb3JCbHVlLCBjb2xvclJlZCwgY29sb3JNYWdlbnRhLCBjb2xvckdyZXkpDQogICkNCmBgYA0KTGVzIHpvbmVzIG1peHRlcyBzb250IHBldSBsaXNpYmxlcy4gVXRpbGlzb25zIHVuIGNocm9tYSBwbHVzIGNvbnPDqXF1ZW50IHBvdXIgY2V0dGUgY291bGV1ciA6DQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KZ2dwbG90KGRhdGEgID0gc3RhdFJlZzIsIA0KICAgICAgIGFlcyh4ID0gaWRyZWd0eHQsIA0KICAgICAgICAgICB5ID0gZmx1eCwgDQogICAgICAgICAgIGZpbGwgPSB2YXJpYWJsZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZSgNCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJvcmRlcj1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplID0gOCksDQogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplID0gOCkpICsNCnNjYWxlX2ZpbGxfbWFudWFsKA0KICBuYW1lID0gIkZsdXhcbmQnYXJ0aWZpY2lhbGlzYXRpb25cbjIwMDktMjAyMCIsDQogIGxhYmVscyA9IGMoIkhhYml0YXQiLCAiQWN0aXZpdMOpIiwgIk1peHRlIiwgIkluY29ubnUiKSwNCiAgdmFsdWVzID0gYyhjb2xvckJsdWUsIGNvbG9yUmVkLCBnZXRDb2xvckZvckh1ZShoID0gMzAwLCBjID0gMTAwKSwgY29sb3JHcmV5KQ0KICApDQpgYGANCg0KDQojIyBSZXByw6lzZW50YXRpb24gZW4gYmFycmVzIHBhciBkw6lwYXJ0ZW1lbnQgcG91ciB1bmUgcsOpZ2lvbg0KDQpGYWlzb25zIGxlIG3Dqm1lIGdyYXBoaXF1ZSwgbWFpcyBwb3VyIHRvdXMgbGVzIGTDqXBhcnRlbWVudHMgZGUgUHJvdmVuY2UuDQoNClRyYW5zZm9ybW9ucyBub3Mgc3RhdHMgZMOpcGFydGVtZW50YWxlcy4NCg0KTm91cyBhbGxvbnMgZW4gcHJvZml0ZXIgcG91ciByZW5kcmUgbGVzIGNob3NlcyB1biBwZXUgcGx1cyBnw6luw6lyaXF1ZXMuDQoNClRvdXQgZCdhYm9yZCwgbGVzIGRldXggcHJlbWnDqHJlcyBjb2xvbm5lcyBjb3JyZXNwb25kZW50IGF1eCBjb2RlIGV0IGxpYmVsbMOpcy4gTGVzIGF1dHJlcyBjb2xvbm5lcyBjb25jZXJuZW50IGxlcyBmbHV4Lg0KDQpgYGB7cn0NCnN0YXREZXAyIDwtIGdhdGhlcihzdGF0RGVwLCANCiAgICAgICAidmFyaWFibGUiLCANCiAgICAgICAiZmx1eCIsIA0KICAgICAgIGMoImFydGFjdDA5MjAiLCAiYXJ0aGFiMDkyMCIsICJhcnRtaXgwOTIwIiwgImFydGluYzA5MjAiKSkNCg0Kc3RhdERlcDMgPC0gc3RhdERlcDIgJT4lIHJlbmFtZShjb2RlID0gMSwgbGliZWxsZSA9IDIpDQpgYGANCg0KTm91cyB0cmlvbnMgbGVzIG5pdmVhdXggZGUgZmFjdGV1cnMgY2FyIGNldXgtY2kgZMOpdGVybWluZW50IGwnb3JkcmUgZGFucyBsZXF1ZWwgbGVzIMOpbMOpbWVudHMgc29udCBhZmZpY2jDqXMgZGFucyBsZSBncmFwaGlxdWUuDQoNCk5vdXMgc291aGFpdG9ucyByw6lnbGVyIGwnYWZmaWNoYWdlIGRlcyBlbnRpdMOpcyBzZWxvbiBsZXVyIG5vbSAoZMOpcGFydGVtZW50cyBvdSByw6lnaW9ucyksIGFpbnNpIHF1ZSBjZWx1aSBkZXMgdmFyaWFibGVzIChmbHV4IGQnaGFiaXRhdCwgYWN0aXZpdMOpLCAuLi4pDQoNCiEhIQ0KDQpDcsOpb25zIHVuZSBmb25jdGlvbiBxdWkgcHJvZHVpdCBsZSBncmFwaGlxdWUgc3VyIGxhIGJhc2UgZGUgY2UgZGF0YSBmcmFtZSBnw6luw6lyaXF1ZS4gT24gcmVwcmVuZCBsZSBjb2RlIHByw6ljw6lkZW50IDoNCmBgYHtyfQ0KbWFrZVBsb3QgPC0gZnVuY3Rpb24oZGYpIHsNCiAgDQogICMgUmVsZXZlbA0KICBkZiRsaWJlbGxlIDwtIGFzLmNoYXJhY3RlcihkZiRsaWJlbGxlKQ0KICBkZiRsaWJlbGxlIDwtIGZhY3RvcihkZiRsaWJlbGxlLCBsZXZlbHMgPSBzb3J0KHVuaXF1ZShkZiRsaWJlbGxlKSwgZGVjcmVhc2luZyA9IFRSVUUpKQ0KDQogIGRmJHZhcmlhYmxlIDwtIGFzLmNoYXJhY3RlcihkZiR2YXJpYWJsZSkNCiAgZGYkdmFyaWFibGUgPC0gZmFjdG9yKGRmJHZhcmlhYmxlLCBsZXZlbHMgPSBjKCJhcnRoYWIwOTIwIiwiYXJ0YWN0MDkyMCIsICJhcnRtaXgwOTIwIiwgImFydGluYzA5MjAiKSkNCiAgDQogICMgQ29sb3JzDQogIGNvbG9yQmx1ZSA8LSBnZXRDb2xvckZvckh1ZSgyMjApDQogIGNvbG9yUmVkIDwtIGdldENvbG9yRm9ySHVlKDQpDQogIGNvbG9yTWFnZW50YSA8LSBnZXRDb2xvckZvckh1ZShoID0gMzAwLCBjID0gMTAwKQ0KICBjb2xvckdyZXkgPC0gaGNsKGggPSAwLCBjID0gMCwgbCA9IDgwLCBmaXh1cCA9IFRSVUUpDQogIHBhbGV0dGUgPC0gYyhjb2xvckJsdWUsIGNvbG9yUmVkLCBjb2xvck1hZ2VudGEsIGNvbG9yR3JleSkNCg0KICAjIFBsb3QNCiAgZ2dwbG90KGRhdGEgID0gZGYsIA0KICAgICAgICAgYWVzKHggPSBsaWJlbGxlLCANCiAgICAgICAgICAgICB5ID0gZmx1eCwgDQogICAgICAgICAgICAgZmlsbCA9IHZhcmlhYmxlKSkgKw0KICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIHRoZW1lKA0KICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLA0KICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCgNCiAgICBuYW1lID0gIkZsdXhcbmQnYXJ0aWZpY2lhbGlzYXRpb25cbjIwMDktMjAyMCIsDQogICAgbGFiZWxzID0gYygiSGFiaXRhdCIsICJBY3Rpdml0w6kiLCAiTWl4dGUiLCAiSW5jb25udSIpLA0KICAgIHZhbHVlcyA9IHBhbGV0dGUNCiAgICApDQp9DQoNCm1ha2VQbG90KHN0YXREZXAzICU+JSBmaWx0ZXIoY29kZSAlaW4lIGMoIjA0IiwgIjA1IiwgIjA2IiwgIjEzIiwgIjgzIiwgIjg0IikpKQ0KYGBgDQoNCk5vdXMgcG91dm9ucyB1dGlsaXNlciBjZXR0ZSBmb25jdGlvbiBzdXIgbGVzIHN0YXRzIHLDqWdpb25hbGVzIDoNCg0KYGBge3J9DQpzdGF0UmVnMiAlPiUgcmVuYW1lKGNvZGUgPSAxLCBsaWJlbGxlID0gMikgJT4lIG1ha2VQbG90KCkNCmBgYA0KT24gcGV1dCBkb25jIHV0aWxpc2VyIGxhIG3Dqm1lIGZvbmN0aW9uIHN1ciBuJ2ltcG9ydGUgcXVlbCBmaWNoaWVyIHN0YXRpc3RpcXVlcyBkZSBmbHV4LiBOb3VzIHBvdXJyaW9ucyBhdXNzaSBsJ3V0aWxpc2VyIHN1ciBkZXMgY29tbXVuZXMgOg0KDQohISENCiEhIGRhdGEydml6DQohISBzdHlsZXMNCiMjIFJlcHLDqXNlbnRhdGlvbiBlbiB0cmVlbWFwDQpMYSByZXByw6lzZW50YXRpb24gZW4gdHJlZW1hcCBlc3QgcGFzIG1hbCBwb3VyIHByw6lzZW50ZXIgbGVzIGZsdXggZCdhcnRpZmljaWFsaXNhdGlvbiBzdXIgdW5lIGNvbW11bmUuDQoNClByZW5vbnMgcGFyIGV4ZW1wbGUgbGEgY29tbXVuZSBkJ0FpeCBlbiBQcm92ZW5jZSA6DQpgYGB7cn0NCmZBaXggPC0gZiAlPiUgZmlsdGVyKGlkY29tID09ICIxMzAwMSIpICU+JSBzZWxlY3QoImFydGhhYjA5MjAiLCAiYXJ0YWN0MDkyMCIsICJhcnRtaXgwOTIwIiwgImFydGluYzA5MjAiKQ0KZkFpeA0KYGBgDQoNCkxlIHBhY2thZ2UgcGxvdGx5IHBlcm1ldCBkZSBjcsOpZXIgY2Ugc3R5bGUgZGUgcmVwcsOpc2VudGF0aW9uDQoNCnRyZWVtYXAgYXR0ZW5kIC4uLiAhISENCg0KYGBge3J9DQpsaWJyYXJ5KHBsb3RseSkNCg0KbGFiZWxzID0gYygiSGFiaXRhdCIsICJBY3Rpdml0w6kiLCAiTWl4dGUiLCAiTkMiKSAjICEhIE5DDQpwYXJlbnRzID0gYygiIiwgIiIsICIiLCAiIikNCnZhbHVlcyA9IGFzLm51bWVyaWMoZkFpeCkNCg0KZmlnIDwtIHBsb3RfbHkoDQogIHR5cGUgPSAidHJlZW1hcCIsDQogIGxhYmVscyA9IGxhYmVscywNCiAgcGFyZW50cyA9IHBhcmVudHMsDQogIHZhbHVlcyA9IHZhbHVlcywNCiAgbWFya2VyID0gbGlzdChjb2xvcnNjYWxlPSdSZWRzJykpDQoNCmZpZw0KYGBgDQoNCiEhISBwb3VyIHBsdXNpZXVycyBjb21tdW5lcw0KDQpSZXByw6lzZW50YXRpb24gZW4gc3RyZWFtZ3JhcGgNCg0KVm95b25zIGwnw6l2b2x1dGlvbiBhdSBjb3VycyBkdSB0ZW1wcyBkZXMgZmx1eA==